home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Devices and Hardware / SCSI / SCSI Inquiry (More) / SCSI Inquiry(Simple) / SCSIInquiry(simple).c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  8.1 KB  |  277 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        SCSIInquiry(simple).c
  3.  
  4.     Contains:    This is a minimal sample to illustrate the Old SCSI Manager.
  5.  
  6.     Written by: Martin Minow    
  7.  
  8.     Copyright:    Copyright ©1994-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 7/15/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23. #include "SCSIInquiry.h"
  24.  
  25. #ifndef THINK_C                /* MPW includes            */
  26. #include <Errors.h>
  27. #include <Script.h>
  28. #include <Types.h>
  29. #include <Files.h>
  30. #include <Resources.h>
  31. #include <QuickDraw.h>
  32. #include <Fonts.h>
  33. #include <Events.h>
  34. #include <Windows.h>
  35. #include <ToolUtils.h>
  36. #include <Memory.h>
  37. #include <Menus.h>
  38. #include <Lists.h>
  39. #include <Printing.h>
  40. #include <Dialogs.h>
  41. #include <StandardFile.h>
  42. #include <TextUtils.h>
  43. #endif
  44.  
  45. #include <SCSI.h>
  46.  
  47. unsigned short            gTargetDevice = 0;    /* Using device at ID = 0    */
  48.  
  49. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  50.  * SCSI Definitions
  51.  */
  52. #define    kScsiStatusGood            0x00        /* Normal completion        */
  53. #define    kScsiCmdInquiry            0x12        /* Device inquiry command    */
  54.  
  55. struct SCSI_6_Byte_Command {                /* Six-byte command            */
  56.     unsigned char        opcode;                /*  0                        */
  57.     unsigned char        lbn3;                /*  1 lbn in low 5            */
  58.     unsigned char        lbn2;                /*  2                        */
  59.     unsigned char        lbn1;                /*  3                        */
  60.     unsigned char        len;                /*  4                        */
  61.     unsigned char        ctrl;                /*  5                        */
  62. };
  63. typedef struct SCSI_6_Byte_Command SCSI_6_Byte_Command;
  64.  
  65. struct SCSI_Inquiry_Data {                    /* Inquiry returns this        */
  66.     unsigned char        devType;            /*  0 Device type,            */
  67.     unsigned char        devTypeMod;            /*  1 Device type modifier    */
  68.     unsigned char        version;            /*  2 ISO/ECMA/ANSI version    */
  69.     unsigned char        format;                /*  3 Response data format    */
  70.     unsigned char        length;                /*  4 Additional Length        */
  71.     unsigned char        reserved5;            /*  5 Reserved                */
  72.     unsigned char        reserved6;            /*  6 Reserved                */
  73.     unsigned char        flags;                /*  7 Capability flags        */
  74.     unsigned char        vendor[8];            /*  8-15 Vendor-specific    */
  75.     unsigned char        product[16];        /* 16-31 Product id            */
  76.     unsigned char        revision[4];        /* 32-35 Product revision    */
  77.     unsigned char        vendorSpecific[20]; /* 36-55 Vendor stuff        */
  78.     unsigned char        moreReserved[40];    /* 56-95 Reserved            */
  79. };
  80. typedef struct SCSI_Inquiry_Data SCSI_Inquiry_Data;
  81.  
  82. SCSI_Inquiry_Data            gInquiryData;    /* Inquiry data goes here    */
  83. unsigned long                gInquirySize;    /* Number of bytes read        */
  84.  
  85. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  86.  * gSCSICommand is the command that we send to the device.
  87.  */
  88. SCSI_6_Byte_Command            gSCSICommand = {
  89.         kScsiCmdInquiry,                    /* Command                    */
  90.         0,                                    /* LBN 3 -- unused            */
  91.         0,                                    /* LBN 2 -- unused            */
  92.         0,                                    /* LBN 1 -- unused            */
  93.         sizeof (SCSI_Inquiry_Data),            /* Returned buffer length    */
  94.         0                                    /* Flags -- must be zero    */
  95.     };
  96.  
  97. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  98.  * gRequestTIB defines the buffer that SCSIRead reads into. Because
  99.  * the Inquiry command can return a variable-length record, we use a
  100.  * TIB with single-byte transfers and an internal counter so we can
  101.  * recover the actual transfer length. The four tib values are used
  102.  * as follows:
  103.  *        scInc...    Move one byte from the device to the buffer address
  104.  *                    and increment the buffer address pointer.
  105.  *        scAdd...    Add one to gInquirySize -- this gives the actual
  106.  *                    number of bytes transfered.
  107.  *        scLoop        Continue processing TIB instructions at the start
  108.  *                    until the maximum number of loops have been done.
  109.  *        scStop        End of the TIB.
  110.  * Note that this is an extremely inefficient TIB and should only be
  111.  * used for polled "administrative" requests that return a variable-
  112.  * length buffer.
  113.  */
  114. SCSIInstr                    gRequestTIB[] = {
  115.     { scInc,    0, 1 },
  116.     { scAdd,    0, 1 },
  117.     { scLoop,    (-2 * sizeof (SCSIInstr)),    sizeof (SCSI_Inquiry_Data)    },
  118.     { scStop,    0,                                0 }
  119. };
  120.  
  121. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  122.  * Local functions and administrative variables.
  123.  */
  124. #ifdef __powerc
  125. QDGlobals                qd;
  126. #endif
  127.  
  128. void                        DisplayError(
  129.         OSErr                    errorStatus
  130.     );
  131. OSErr                        DoSCSICommand(
  132.         unsigned short            targetID,
  133.         const Ptr                scsiCommand,
  134.         SCSIInstr                *requestTIB
  135.     );
  136. void                        DisplaySCSIInquiry(
  137.         long                    actualTransferCount
  138.     );
  139.  
  140. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  141.  * Local functions and administrative variables.
  142.  */
  143. void
  144. main(void)
  145. {
  146.         short                    i;
  147.         OSErr                    status;
  148.         OSErr                    completionStatus;
  149.         EventRecord                eventRecord;
  150.         long                    actualTransferCount;
  151.         unsigned long            watchdog;
  152.         short                    stsByte;
  153.         short                    msgByte;
  154.             
  155.         MaxApplZone();        
  156.         InitGraf(&qd.thePort);
  157.         InitFonts();
  158.         InitWindows();
  159.         InitMenus();
  160.         TEInit();
  161.         InitDialogs(0);
  162.         for (i = 0; i < 3; i++)
  163.             EventAvail(everyEvent, &eventRecord);
  164.         gRequestTIB[0].scParam1 = (unsigned long) &gInquiryData;
  165.         gRequestTIB[1].scParam1 = (unsigned long) &gInquirySize;
  166.         /*
  167.          * This is a simplified form of the "Get Bus" protocol.
  168.          */
  169.         watchdog = TickCount() + 300;
  170.         while ((status = SCSIGet()) != noErr && TickCount() < watchdog)
  171.             ;
  172.         if (status == noErr)
  173.             status = SCSISelect(gTargetDevice);
  174.         if (status == noErr) {
  175.             status = SCSICmd((Ptr) &gSCSICommand, sizeof gSCSICommand);
  176.             if (status == noErr)
  177.                 status = SCSIRead((Ptr) gRequestTIB);
  178.             completionStatus = SCSIComplete(&stsByte, &msgByte, 5 * 60);
  179.             if (status == noErr && completionStatus != noErr)
  180.                 status = completionStatus;
  181.             if (status == scPhaseErr && stsByte == kScsiStatusGood)
  182.                 status = noErr;
  183.             if (status == noErr && stsByte != kScsiStatusGood)
  184.                 status = ioErr;
  185.         }
  186.         /*
  187.          * Since the Device Inquiry command can return a variable-length
  188.          * record, we need to obtain the actual number of bytes that
  189.          * were read. There are two algorithms we can use here, that
  190.          * should result in the same data:
  191.          *    Since tib[0].scOpcode was scInc, tib[0].scParam1 will point to
  192.          *        the next byte to store. We can subtract the original buffer
  193.          *        pointer from that value to get the actual count.
  194.          *    Since tib[1].scOpcode was scAdd, gInquirySize will have the
  195.          *        actual count.
  196.          *    One or another of these two techniques can be used for this
  197.          *    type of data.
  198.          */
  199.         actualTransferCount =
  200.             gRequestTIB[0].scParam1 - (unsigned long) &gInquiryData;
  201.         if (actualTransferCount != gInquirySize)
  202.             DisplayError(paramErr);
  203.         if (status != noErr)
  204.             DisplayError(status);
  205.         DisplaySCSIInquiry(actualTransferCount);
  206.         ExitToShell();
  207. }
  208.  
  209.  
  210. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  211.  * Display the inquiry result.
  212.  */
  213. static void
  214. StoreString(
  215.         const unsigned char        *textPtr,
  216.         Size                    textLength,
  217.         StringPtr                result
  218.     )
  219. {
  220.         register short            i;
  221.         
  222.         for (i = textLength; i > 0; --i) {
  223.             if (textPtr[i - 1] != ' ' && textPtr[i - 1] != 0)
  224.                 break;
  225.         }
  226.         BlockMove(textPtr, &result[1], i);
  227.         result[0] = i;
  228. }
  229.  
  230. void
  231. DisplaySCSIInquiry(
  232.         long                    actualTransferCount
  233.     )
  234. {
  235.         Str255                    inquirySize;
  236.         Str255                    vendorName;
  237.         Str255                    productName;
  238.         Str255                    revisionLevel;
  239.         
  240.         NumToString(actualTransferCount, inquirySize);
  241.         StoreString(
  242.             gInquiryData.vendor,
  243.             sizeof gInquiryData.vendor,
  244.             vendorName
  245.         );
  246.         StoreString(
  247.             gInquiryData.product,
  248.             sizeof gInquiryData.product,
  249.             productName
  250.         );
  251.         StoreString(
  252.             gInquiryData.revision,
  253.             sizeof gInquiryData.revision,
  254.             revisionLevel
  255.         );
  256.         ParamText(inquirySize, vendorName, productName, revisionLevel);
  257.         NoteAlert(ALRT_Info, NULL);
  258. }
  259.  
  260.  
  261. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  262.  * Display an error alert.
  263.  */
  264. void
  265. DisplayError(
  266.         OSErr                    errorStatus
  267.     )
  268. {
  269.         Str255                    work;
  270.         
  271.         NumToString(errorStatus, work);
  272.         ParamText(work, "\p", "\p", "\p");
  273.         InitCursor();
  274.         StopAlert(ALRT_Error, NULL);
  275. }
  276.  
  277.